package com.example.communist_app_api.service.impl;

import com.example.communist_app_api.common.constant.RedisConstant;
import com.example.communist_app_api.config.mq.NoticeTask;
import com.example.communist_app_api.db.dao.MessageDao;
import com.example.communist_app_api.db.dao.OrganizationDao;
import com.example.communist_app_api.db.dao.UserSonmessageDao;
import com.example.communist_app_api.db.dto.*;
import com.example.communist_app_api.db.pojo.Message;
import com.example.communist_app_api.db.pojo.Organization;
import com.example.communist_app_api.db.pojo.UserSonmessage;
import com.example.communist_app_api.exception.GlobalException;
import com.example.communist_app_api.service.MessageService;
import com.example.communist_app_api.service.UserOrganizationService;
import com.example.communist_app_api.util.RedisUtil;
import com.example.communist_app_api.util.StringUtil;
import com.example.communist_app_api.vo.web.req.MessageAuditShowReq;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Brother Sheng Editor
 * @version 1.0
 * Create by 2023/3/1 22:22
 */
@Service
@Transactional
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageDao messageDao;

    @Autowired
    private UserSonmessageDao userSonmessageDao;

    @Autowired
    private UserOrganizationService userOrganizationService;

    @Autowired
    private OrganizationDao organizationDao;

    @Autowired
    private NoticeTask noticeTask;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void createMessage(String content,List<String> photoUrlList ,Integer userId) {
        //list转String字符存储
        String photoUrl = photoUrlList.stream().collect(Collectors.joining(","));
        Integer id = messageDao.insert(content,photoUrl,userId);
        //更新redis缓存需要审批通过才行
        if (id ==null) {
            throw new GlobalException("新增留言异常");
        }
    }

    @Override
    public void createMessageBySystem(String content, Integer userId, int auditor_id) {
        Integer id = messageDao.insertBySystem(content,userId,auditor_id);
        if (id ==null) {
            throw new GlobalException("新增留言异常");
        }
        //删除缓存
        redisUtil.del(RedisConstant.User_Message_Key+userId);
        //重新加载个人留言中心
        personalMessageCenter(userId);
    }
    //重点mybatis返回自增主键问题
    @Override
    public Integer createSonMessageBySystem(String content, Integer messageId, Integer userId, int auditorId) {
        UserSonmessage userSonmessage = new UserSonmessage();
        userSonmessage.setContent(content);
        userSonmessage.setMessageId(messageId);
        userSonmessage.setUserId(userId);
        userSonmessage.setAuditorId(auditorId);
        Integer num = userSonmessageDao.insertBySystem(userSonmessage);
        if (num ==null) {
            throw new GlobalException("新增子留言异常");
        }
        //删除缓存
        redisUtil.del(RedisConstant.User_Message_Key+userId);
        //重新加载个人留言中心
        personalMessageCenter(userId);
        return userSonmessage.getId();
    }

    @Override
    public void createSonMessage(String content, Integer messageId, Integer userId) {
        Integer id = userSonmessageDao.insert(content,messageId,userId);
        if (id ==null) {
            throw new GlobalException("新增子留言异常");
        }
    }

    @Override
    public List<MessageDTO> selectMessageByCondition(String content) {
        List<MessageDTO> messageDTOList;
        if (StringUtil.isNotEmpty(content)) {
            //判断不为空的时候进行模糊查找
             messageDTOList = messageDao.findAllMessage(content);
             messageDTOList.forEach(n->{
                 if (StringUtil.isNotEmpty(n.getPhotoUrl())) {
                     List<String> photoUrlList= Arrays.asList(n.getPhotoUrl().split(","));
                     n.setPhotoUrlList(photoUrlList);
                 }
                 List<SonMessageDTO> sonMessageDTOList= userSonmessageDao.selectAllSonMessageByMessageId(n.getId());
                 if (sonMessageDTOList != null &&sonMessageDTOList.size() != 0) {
                     n.getSonMessageDTOList().addAll(sonMessageDTOList);
                 }
             });
            return messageDTOList;
        }
        //判断content为空正常查询
        //先在redis缓存中查找
        //强转问题转两次就好了List<MessageDTO> messageDTOList= (List<MessageDTO>)(Object)objectList;
        long end = redisUtil.lGetListSize(RedisConstant.All_Message_Key);
        List<Object> objectList=   redisUtil.lGet(RedisConstant.All_Message_Key,0,end);
         messageDTOList= (List<MessageDTO>)(Object)objectList;
        if(CollectionUtils.isEmpty(messageDTOList)){
            //如果为空就去数据库中查询
            //逻辑先找出所有的父留言，然后根据父留言去找子留言
            messageDTOList = messageDao.findAllMessage(content);
            messageDTOList.forEach(n->{
                List<SonMessageDTO> sonMessageDTOList= userSonmessageDao.selectAllSonMessageByMessageId(n.getId());
                if (sonMessageDTOList != null &&sonMessageDTOList.size() != 0) {
                    //n.getSonMessageDTOList()为空
                    n.setSonMessageDTOList(sonMessageDTOList);
                }
            });
            redisUtil.lSet(RedisConstant.All_Message_Key,messageDTOList);
        }
        return messageDTOList;
    }

    public void refresh(){
        //刷新一下缓存
        redisUtil.del(RedisConstant.All_Message_Key);
        selectMessageByCondition(null);
    }

    @Override
    public List<MessageDTO> personalMessageCenter(Integer userId) {
        List<MessageDTO> messageDTOList;
        //缓存用User_Message_Key+用户Id
        long end = redisUtil.lGetListSize(RedisConstant.User_Message_Key+ userId);
        List<Object> objectList=  redisUtil.lGet(RedisConstant.User_Message_Key+userId,0,end-1);
        messageDTOList= (List<MessageDTO>)(Object)objectList;
        if (CollectionUtils.isEmpty(messageDTOList)) {
            //查询数据库
            //先查找用户在子留言发表的言论
            //父留言的IdList
            List<Integer> messageIdList = messageDao.findAllMessageIdByUserId(userId);
            //子留言SonMessageDTOList
            List<SonMessageDTO> sonMessageDTOList = userSonmessageDao.findAllSonMessageByUserId(userId);
            //获取子留言中父留言Id messageIdList
            List<Integer> parentMessageIdList = sonMessageDTOList.stream().map(n -> n.getMessageId()).collect(Collectors.toList());
            //父留言Id和子留言的MessageId合在一起
            //bug问题记录：### Cause: java.lang.UnsupportedOperationException,出现原因
            /**
             * 经过排查发现在对placementIdList赋值的时候, 使用了Arrays.asList, 将数组转换成集合操作.
             * 而Arrays.asList出来的ArrayList是Arrays自定义的，它没有完全实现List的方法，
             * 只是集成了AbstractList<E>，其与我们熟知的通用的ArrayList类不同,
             * ArrayList类是直接实现了List 接口，实现了List所有方法。
             * 所以Arrays.ArrayList是一个定长集合，可以使用set方法。
             * 但是因为它没有重写add,remove方法，所以一旦初始化元素后，集合的size就是不可变的。
             * 由于asList产生的集合并没有重写add,remove等方法，所以它会调用父类AbstractList的方法，
             * 而父类的方法中抛出的却是异常信息UnsupportedOperationException , UnsupportedOperation指的是不支持的操作 .
             * 以后再遇到此类错误, 首先考虑是否是因为对使用Arrayt.asList生成的集合进行伸缩操作引起的.
             */

            /*
              解决办法：转成普通的list
             */
            parentMessageIdList.addAll(messageIdList);
            //转成普通的List
            List<Integer> commonArrayList = new ArrayList<>(parentMessageIdList);
            //去重之后
            List<Integer> distinctMessageIdList = commonArrayList.stream().distinct().collect(Collectors.toList());
            //查询所有父留言
            messageDTOList = messageDao.findAllMessageById(distinctMessageIdList);

            //组装,考虑重复问题，一条父留言中一个用户评论了两次，具有相同的messageId
            /**
             * AtomicInteger i = new AtomicInteger();
             * int finalI = i.get();
             * i.getAndIncrement();
             */
            Map<Integer, MessageDTO> messageDTOMap = messageDTOList.stream().collect(Collectors.toMap(MessageDTO::getId, messageDTO -> messageDTO));
            sonMessageDTOList.forEach(n->{
                if (messageDTOMap.get(n.getMessageId())!= null) {
                    if ( messageDTOMap.get(n.getMessageId()).getSonMessageDTOList() != null) {
                        messageDTOMap.get(n.getMessageId()).getSonMessageDTOList().add(n);
                    }else {
                        ArrayList<SonMessageDTO> sonMessageDTOArrayList = new ArrayList<>();
                        sonMessageDTOArrayList.add(n);
                        messageDTOMap.get(n.getMessageId()).setSonMessageDTOList(sonMessageDTOArrayList);
                    }
                }
            });
            List<MessageDTO> messageDTOListS = messageDTOMap.values().stream().collect(Collectors.toList());
            messageDTOListS.stream().forEach(n->{
                if (StringUtil.isNotEmpty(n.getPhotoUrl())) {
                    List<String> photoUrlList= Arrays.asList(n.getPhotoUrl().split(","));
                    n.setPhotoUrlList(photoUrlList);
                }
            });
            messageDTOList = messageDTOListS.stream().sorted(Comparator.comparing(MessageDTO::getCreatedTime)).collect(Collectors.toList());
            redisUtil.lSet(RedisConstant.User_Message_Key+ userId,messageDTOList);
        }
        return messageDTOList;
    }

    /**
     *
     * @param messageId
     * @param sonMessageId
     * @param userId 当前操作这个方法的用户
     * @param receiverId 发布这条留言的用户
     */
    @Override
    public void personalMessageCenterDelete(Integer messageId, Integer sonMessageId, Integer userId,Integer receiverId) {
        //考量问题
        /**
         * 1.删除messageId时,考虑是否有子评论,有子评论就删除子评论先，删除子评论之后 <刷新当前父评论下的子评论中所有用户的个人消息中心的redis缓存>
         *     同时刷新当前userId用户的redis缓存
         * 2.删除sonMessageId时，刷新当前用户userId的redis缓存
         * 3.对于留言板中不用处理,有定时任务5分钟刷新redis缓存
         */
        String content ="";
        if (messageId != null && sonMessageId !=null) {
            throw new GlobalException("传输messageId和sonMessageId不能同时有值");
        } else if (messageId != null) {
            //根据messageId查询content
            content =messageDao.findContentByMessageId(messageId);
            //统计messageId下的userId
            List<Integer> userIdList = userSonmessageDao.findUserIdListByMessageId(messageId);
            userIdList.add(userId);
            userSonmessageDao.deleteSonMessageByMessageId(messageId);
            messageDao.deleteMessageById(messageId);
            List<Integer> distinctUserIdList = userIdList.stream().distinct().collect(Collectors.toList());
            distinctUserIdList.forEach(n->
            {
                //先删除缓存
                redisUtil.del(RedisConstant.User_Message_Key+n);
                //再调用方法，重新插入redis缓存
                personalMessageCenter(n);
            });
        }else if (sonMessageId !=null){
            //根据sonMessageId查询content
            content =userSonmessageDao.findContentBySonMessageId(sonMessageId);
            userSonmessageDao.deleteSonMessageById(sonMessageId);
            //先删除缓存
            redisUtil.del(RedisConstant.User_Message_Key+userId);
            //再调用方法，重新插入redis缓存
            personalMessageCenter(userId);
        }else if (messageId ==null && sonMessageId ==null){
            throw new GlobalException("传输messageId和sonMessageId不能同时为空");
        }
        //判断，情况一在小程序uniApp上进行留言的操作，userId == receiverId
        //情况二在web端进行留言的删除操作是非发布的人进行删除操作，需要发送消息告知（存在web端删除自己发布的消息，但由于是自己删除，自己已经知情，所以不需要发送消息给自己）
        if (userId != receiverId){
            String title = "建档献策";
            String message = "很抱歉！你发布的建言献策留言被管理员删除请须知！内容为："+content;

            noticeTask.sendNotice(userId, String.valueOf(receiverId),title,message);
        }

    }

    @Override
    public PageInfo<MessageDTO> selectMessageByConditionByWeb(String content, Date startTime, Date endTime, Integer pageSize, Integer pageNum,Integer userId) {
        Page<MessageDTO> page = new Page<>(pageNum,pageSize);
        PageHelper.startPage(pageNum,pageSize);
        Integer skip= (pageNum-1)*pageSize;
        //TODO bug和优化方向，只模糊查找了父留言，子留言没有查到
        //判断组织在上面等级党总支？党支部？
        //根据userId去查询OrganizationId
        Organization organization = userOrganizationService.getOrganizationByUserId(userId);
        //判断当前组织层级是哪一个层级
        Integer grandParentId = organizationDao.getOrganizationByOrganizationId(organization.getParentId()).getParentId();
        List<Integer> organizationIdList = new ArrayList<>();
        organizationIdList.add(organization.getId());
        if (grandParentId == 0){
            //说明该层级是党总支部,获取总支和下面支部的所有留言
            organizationIdList.addAll(organizationDao.getOrganizationIdListByParentId(organization.getId()));
        }else {
            //说明该层级是党支部，获取党总支发布的随手拍和本支部发布的留言
            //添加总支到organizationIdList中
            organizationIdList.add(organizationDao.getOrganizationByOrganizationId(organization.getParentId()).getId());
        }
        List<MessageDTO> messageDTOList = messageDao.findAllMessageByWeb(content,startTime,endTime,organizationIdList);
        messageDTOList.forEach(n->{
            if (StringUtil.isNotEmpty(n.getPhotoUrl())) {
                List<String> photoUrlList= Arrays.asList(n.getPhotoUrl().split(","));
                n.setPhotoUrlList(photoUrlList);
            }
            List<SonMessageDTO> sonMessageDTOList= userSonmessageDao.selectAllSonMessageByMessageId(n.getId());
            if (sonMessageDTOList != null &&sonMessageDTOList.size() != 0) {
                n.setSonMessageDTOList(sonMessageDTOList);
            }
        });
        page.setTotal(messageDTOList.size());
        List<MessageDTO> MessageDTOList = messageDTOList.stream().skip(skip)
                .limit(pageSize).collect(Collectors.toList());
        page.addAll(MessageDTOList);
        return new PageInfo<>(page);
    }

    @Override
    public PageInfo<MessageAuditDTO> selectAllMessageByAudit(MessageAuditShowReq req,Integer userId) {
        Page<MessageAuditDTO> page=new Page<>(req.getPageNum(),req.getPageSize());
        Integer skip= (req.getPageNum()-1)*req.getPageSize();
        Integer organizationId = userOrganizationService.getOrganizationByUserId(userId).getId();
        List<MessageAuditDTO> list = messageDao.selectAllMessageByAudit(organizationId,req.getContent());
        List<MessageAuditDTO> messageAuditDTOList=new ArrayList<>();
        if(list.size()==0){
            page.addAll(messageAuditDTOList);
            PageInfo<MessageAuditDTO> pageInfo=new PageInfo<>(page);
            return pageInfo;
        }
        messageAuditDTOList = list.stream().map(message -> {
            if (StringUtil.isNotEmpty(message.getPhotoUrl())) {
                List<String> photoUrlList= Arrays.asList(message.getPhotoUrl().split(","));
                message.setPhotoUrlList(photoUrlList);
            }
            return message;
        })
                .collect(Collectors.toList());
        page.setTotal(messageAuditDTOList.size());
        messageAuditDTOList = messageAuditDTOList.stream().skip(skip)
                .limit(req.getPageSize()).collect(Collectors.toList());
        page.addAll(messageAuditDTOList);
        return new PageInfo<>(page);
    }

    @Override
    public Integer updateAuditMessage(Integer messageId, Integer auditorId) {
        return messageDao.updateAuditMessage(messageId,auditorId);
    }

    @Override
    public void deleteMessageByMessageId(Integer messageId) {
        messageDao.deleteMessageById(messageId);
    }

    @Override
    public String findContentByMessageId(Integer messageId) {
        return messageDao.findContentByMessageId(messageId);
    }

    @Override
    public String findContentBySonMessageId(Integer sonMessageId) {
        return userSonmessageDao.findContentBySonMessageId(sonMessageId);
    }

    @Override
    public Message findMessageByMessageId(Integer messageId) {
        return messageDao.findMessageByMessageId( messageId);
    }
}
